package cn.yeziji.netty.factory;

import cn.yeziji.netty.adapter.CommunicationAdapters;
import io.netty.channel.ChannelHandlerContext;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 消息接口处理
 *
 * @author gzkemays
 * @since 2022/11/08 12:39 PM
 */
public class MessageInvocationHandler implements InvocationHandler {
  private final CommunicationAdapters communicationAdapters;

  public MessageInvocationHandler(CommunicationAdapters communicationAdapters) {
    this.communicationAdapters = communicationAdapters;
  }

  /**
   * 执行动态代理方法
   *
   * @param proxy 代理的对象
   * @param method 执行的方法
   * @param args 方法参数
   * @return 执行结果
   * @throws Throwable 参数不正确等异常
   */
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) {
    try {
      return CommunicationAdapters.class
          .getMethod(method.getName(), ChannelHandlerContext.class)
          .invoke(communicationAdapters, args);
    } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
      e.printStackTrace();
      throw new RuntimeException(e);
    }
  }

  /**
   * 根据传参获取类并返回 Class<?> 数组
   *
   * @param args 传入参数
   * @return Class<?>
   */
  public static Class<?>[] getClazzByArgs(Object[] args) {
    Class<?>[] parameterTypes = new Class[args.length];
    for (int i = 0; i < args.length; i++) {
      if (args[i] instanceof ArrayList) {
        parameterTypes[i] = List.class;
        continue;
      }
      if (args[i] instanceof LinkedList) {
        parameterTypes[i] = List.class;
        continue;
      }
      if (args[i] instanceof HashMap) {
        parameterTypes[i] = Map.class;
        continue;
      }
      if (args[i] instanceof Long) {
        parameterTypes[i] = long.class;
        continue;
      }
      if (args[i] instanceof Double) {
        parameterTypes[i] = double.class;
        continue;
      }
      if (args[i] instanceof TimeUnit) {
        parameterTypes[i] = TimeUnit.class;
        continue;
      }
      parameterTypes[i] = args[i].getClass();
    }
    return parameterTypes;
  }
}
